package com.gjs.freechat.server.component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.gjs.freechat.server.component.bean.ChatSession;
import com.gjs.freechat.server.component.bean.Conversation;
import com.gjs.freechat.server.component.bean.UserInfo;



@Component
public class UserMatchManage {
	
	@Autowired
	private UsersPoolManage usersPool;
	
	@Autowired
	private UserSessionPool sessionPool;
	
	private List<UserInfo> waitingMatchUsers;
	
	private Map<String, List<Conversation>> waitingConvos;
	
	private AtomicInteger queryingNum; 
	
	public UserMatchManage() {
		waitingMatchUsers = Collections.synchronizedList(new LinkedList<UserInfo>());
		waitingConvos = new ConcurrentHashMap<String, List<Conversation>>();
		queryingNum = new AtomicInteger(0);
	}
	
	public void addConvo(UserInfo userInfo, Conversation convo) {
		synchronized (userInfo) {
			List<Conversation> convos = waitingConvos.get(userInfo.getId());
			if (convos == null) {
				convos = Collections.synchronizedList(new LinkedList<Conversation>());
				waitingConvos.put(userInfo.getId(), convos);
			}
			System.out.println(userInfo.getId() + ":add-convo");
			convos.add(convo);
			if (convos.size() == 1) {
				waitingMatchUsers.add(userInfo);
			}
		}	
	}
	
	public void removeConvo(UserInfo userInfo, Conversation convo) {
		List<Conversation> convos = waitingConvos.get(userInfo.getId());
		synchronized (convos) {
			System.out.println(userInfo.getId() + ":removeConvo");
			convos.remove(convo);
			if (convos.size() == 0) {
				waitingMatchUsers.remove(userInfo);
				waitingConvos.remove(userInfo.getId());
			}
		}
		
	}
	
	public UserInfo executeMatch(UserInfo userInfo, ChatSession chatSession) {
		//System.out.println(Thread.currentThread() + ":waitingMatchUserSize:" +  waitingMatchUsers.size());
		//queryingNum.incrementAndGet();
		synchronized (userInfo) {
			String userId = userInfo.getId();
			//int size = waitingMatchUsers.size();
//			int randomUserIndex = size <= 0 ? size : RandomUtils.nextInt(size);
//			randomUserIndex = randomUserIndex == 0 ? 1 : randomUserIndex;
//			double maxMatching = 0;
//			for (UserInfo partner : waitingMatchUsers) {
//				if (randomUserIndex-- > 0 || partner.getId().equals(userId))
//					continue;
//				chatSession.setRightUserId(partner.getId());
//				if (!sessionPool.addSession(chatSession))
//					continue;
//				//queryingNum.decrementAndGet();
//				System.out.println(userInfo.getId() + ":findUser-success");
//				return partner;
//			}
			double maxScore = 0;
			UserInfo partner = null;
			for (UserInfo user : waitingMatchUsers) {
				if (user.getId().equals(userId))
					continue;
				double score = UserSimilarity.similarityMeasure(userInfo, user);
				if (maxScore < score) {
					maxScore = score;
					partner = user;
				}
			}
			if (partner == null) {
				return null;
			}
			chatSession.setRightUserId(partner.getId());
			if (sessionPool.addSession(chatSession)) {
				System.out.println(userInfo.getId() + "," + partner.getId() + ",matching score:" + maxScore);
				return partner;
			}
			return null;
		}
	}
	
	public void remove(UserInfo userInfo) {
		waitingMatchUsers.remove(userInfo);
		waitingConvos.remove(userInfo.getId());
	}
	
	public Conversation getRandomConvo(String userId) {
		List<Conversation> convos = waitingConvos.get(userId);
		synchronized (convos) {
			if (convos.size() > 0) {
				System.out.println(userId + ":findConvo");
				int index = RandomUtils.nextInt(convos.size());
				return convos.get(index);
			}
			return null;
		}
	}
	
	public Conversation getConvo(String userId, String convoId) {
		List<Conversation> convos = waitingConvos.get(userId);
		if (convos == null)
			return null;
		for (Conversation convo : convos) {
			if (convo.getId().equals(convoId))
				return convo;
		}
		return null;
	}
	
	public List<Conversation> getConvos(String userId) {
		return waitingConvos.get(userId);
	}
	
	public List<UserInfo> getMatchingUser() {
		return waitingMatchUsers;
	}
	
	public List<String> getMatchingUserIds() {
		List<String> userIds = new ArrayList<String>();
		for (UserInfo user : waitingMatchUsers) {
			userIds.add(user.getId());
		}
		return userIds;
	}
	
}
